﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Dou.Scripts.Core.UI.Base;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class UIGeneratorWindow : OdinEditorWindow
{
    [ReadOnly][HorizontalGroup("gameObject")]public GameObject gameObject;

    [Button("Selection")] [HorizontalGroup("gameObject")]
    public void Select()
    {
        if (gameObject != Selection.activeGameObject)
        {
            OnSave();
            _setting = new UIGeneratorSettings();
            gameObject = Selection.activeGameObject;
        }
        OnLoad();
    }
    [SerializeField] public UIGeneratorSettings _setting = new();

    protected override void OnEnable()
    {
        base.OnEnable();
        gameObject = Selection.activeGameObject;
        OnLoad();
    }

    protected override void OnDisable()
    {
        base.OnDisable();
        OnSave();
    }

    void OnLoad()
    {
        if(_setting == null || !gameObject)return;
        var file = Path.Combine(".uigen", $"{UIGenerator.GetClassName(gameObject)}.json");
        if (File.Exists(file))
        {
            var json = File.ReadAllText(file);
            _setting= JsonUtility.FromJson<UIGeneratorSettings>(json);
            _setting.OnAfterLoad(gameObject);
        }
    }
    private void OnSave()
    {
        if(_setting == null || !gameObject)return;
        _setting.OnBeforeSave(gameObject);
        var json = JsonUtility.ToJson(_setting);
        var file = Path.Combine(".uigen", $"{UIGenerator.GetClassName(gameObject)}.json");
        if(!Directory.Exists(".uigen"))
            Directory.CreateDirectory(".uigen");
        File.WriteAllText(file,json);
    }

    [MenuItem("Tools/UI/UI Generator Window")]
    public static void ShowWindow()
    {
        var w = GetWindow<UIGeneratorWindow>("UI Generator");
        w.Show();
    }
    
    [PropertySpace]
    [Button("生成CSharp"),HorizontalGroup("button")]
    public void Generate()
    {
        new UIGenerator(_setting,gameObject).Generate(); 
    }
    [PropertySpace]
    [Button("添加View"),HorizontalGroup("button")]
    public void AddView()
    {
        string type = _setting.UINameSpace + '.' + UIGenerator.GetClassName(gameObject);
        var t = Assembly.GetAssembly(typeof(BaseView)).GetType(type);
        if (t != null && gameObject.GetComponent(t) == null)
        {
            gameObject.AddComponent(t);
            AssignViewItems();
        }
    }
    
    [PropertySpace]
    [Button("填充对象"),HorizontalGroup("button")]
    public void AssignViewItems()
    {
        string type = _setting.UINameSpace + '.' + UIGenerator.GetClassName(gameObject);
        var tt = Assembly.GetAssembly(typeof(BaseView)).GetType(type);
        var b = gameObject.GetComponent(tt);
        Type t = b.GetType();
        
        Dictionary<string,UIGeneratorSettings.ViewItem> dic = new ();// fieldName + type:item
        foreach (var item in _setting.viewItems)
        {
            string key = UIGenerator.GetMemberName(item);
            dic.Add(key,item);
        }
        
        foreach (var f in t.GetFields(BindingFlags.Instance|BindingFlags.NonPublic))
        {
            string key = f.Name;
            if (dic.ContainsKey(key))
            {
                if(f.FieldType == typeof(GameObject))
                    f.SetValue(b,dic[key].item);
                else 
                    f.SetValue(b,dic[key].item.GetComponent(f.FieldType));
            }
        }
        
        foreach (var f in t.GetProperties(BindingFlags.Instance|BindingFlags.NonPublic))
        {
            string key = f.Name;
            if (dic.ContainsKey(key))
            {
                if(f.PropertyType == typeof(GameObject))
                    f.SetValue(b,dic[key].item);
                else 
                    f.SetValue(b,dic[key].item.GetComponent(f.PropertyType));
            }
        }
    }
}

[Serializable]
public class UIGeneratorSettings 
{
    [Title("Global Settings")]
    [Tooltip("生成的view的命名空间")] public string UINameSpace = "Dou.UI";
    [FolderPath]
    [Tooltip("生成的cs目录")] public string GenPath = "Assets/Dou/Scripts/UI/Views";
    [Title("items")]
    [VerticalGroup,SerializeField,HideLabel] public List<ViewItem> viewItems = new ();
    
    [Serializable]
    public class ViewItem
    {
        [ValueDropdown("ItemValueDropdown",DropdownWidth = 300)]
        [HorizontalGroup,HideLabel] public string component;
        [HorizontalGroup,HideLabel] public GameObject item;
        [HideInInspector, SerializeField] public string path;
        
        List<string> ItemValueDropdown()
        {
            if (item != null)
            {
                var tms = from t in  typeof(TextMeshProUGUI).Assembly.GetTypes()
                    where !(t.Name.StartsWith("I") || t.Name.StartsWith("<"))
                          && t.IsClass && (t.IsSubclassOf(typeof(UIBehaviour)) || t.IsSubclassOf(typeof(Graphic)))
                    select t;
                var comps = from t in typeof(UnityEngine.UI.Text).Assembly.GetTypes()
                    where t .Namespace != null && t.Namespace.Contains("UI") && !(t.Name.StartsWith("I") || t.Name.StartsWith("<"))
                          && t.IsClass && (t.IsSubclassOf(typeof(UIBehaviour)) || t.IsSubclassOf(typeof(Graphic)))
                    select t;

                var its = item.GetComponents<Component>().ToList().Select(f=>f.GetType()).ToList();

                var unity = new List<Type>
                {
                    typeof(Transform),
                    typeof(GameObject),
                    typeof(RectTransform),
                };
                return unity.Concat(its.FindAll(f =>comps.Contains(f) || tms.Contains(f) || f.IsSubclassOf(typeof(MonoBehaviour)))).Select(t=>t.Name).ToList();
            }
            return new List<string>{};
        }
    }
    
    public void OnBeforeSave(GameObject gameObject)
    {
        if(!gameObject)
            return;
        if (viewItems != null && viewItems.Count > 0)
        {
            foreach (var item in viewItems)
            {
                if(!item.item || item.component==null || item.component=="")continue;
                item.path = GetHierachyPath(item.item.transform, gameObject.transform);
            }
        }
    }

    public void OnAfterLoad(GameObject gameObject)
    {
        if(!gameObject)
            return;
        if (viewItems != null && viewItems.Count > 0)
        {
            foreach (var item in viewItems)
                item.item = gameObject.transform.Find(item.path)?.gameObject;
        }
    }
    public string GetHierachyPath(Transform obj,Transform root)
    {
        List<string> path = new();
        while (obj != null && obj != root)
        {
            path.Add(obj.name);
            obj = obj.parent;
        }
        path.Reverse();
        return  string.Join("/", path);
    }

}